#pragma once
#include <pthread.h>
#include <errno.h>
#include <utility>
#include <assert.h>
// #include "LxTypedefs.h"

#ifndef INFINITE
#define INFINITE 0xFFFFFFFF
#endif
#ifndef IN
#define IN
#endif

// 获取pthread中超时的时间
timespec pthread_stoptime(unsigned int dwMilliseconds);
timespec pthread_stoptime(IN timespec &ts, unsigned int dwMilliseconds);

// LxPThread_Event使用pthread_mutex和pthread_cond实现基础的
struct pthread_mutexcond
{
protected:
	pthread_mutex_t mutex;
	pthread_cond_t cond;
	timespec tsStartTime;

public:
	// wait相关函数的返回值，这里只有列出成功和超时，其他都是错误
	enum
	{
		wait_success = 0,
		wait_timeout = ETIMEDOUT
	};

	pthread_mutexcond()
	{
		pthread_mutex_init(&mutex, NULL);
		pthread_cond_init(&cond, NULL);
		tsStartTime.tv_sec = 0;
		tsStartTime.tv_nsec = 0;
	}

	virtual ~pthread_mutexcond()
	{
		pthread_mutex_destroy(&mutex);
		pthread_cond_destroy(&cond);
	}

	void LockMutex()
	{
		pthread_mutex_lock(&mutex);
	}

	void UnlockMutex()
	{
		pthread_mutex_unlock(&mutex);
	}

	void SetUnlockedWaitStartTime()
	{
		clock_gettime(CLOCK_REALTIME, &tsStartTime);
	}

	int UnlockedWait(unsigned int dwMilliseconds = INFINITE)
	{
		if (dwMilliseconds == INFINITE)
			return pthread_cond_wait(&cond, &mutex);

		assert(tsStartTime.tv_sec != 0 && tsStartTime.tv_nsec != 0);
		timespec ts = pthread_stoptime(tsStartTime, dwMilliseconds);
		return pthread_cond_timedwait(&cond, &mutex, &ts);
	}

	int UnlockedWait(timespec &ts)
	{
		if (ts.tv_sec != 0 && ts.tv_nsec != 0)
			return pthread_cond_wait(&cond, &mutex);
			
		return pthread_cond_timedwait(&cond, &mutex, &ts);
	}

	void UnlockedSignal()
	{
		pthread_cond_signal(&cond);
	}

	void UnlockedBroadcast()
	{
		pthread_cond_broadcast(&cond);
	}

	// 由于pthread_cond_wait可能被非signal和broadcast唤醒，所以下面注释的内容其实是没用的
	// int wait(){
	//     pthread_mutex_lock(&mutex);
	//     int result = pthread_cond_wait(&cond, &mutex);
	//     pthread_mutex_unlock(&mutex);
	//     return result;
	//     // std::condition_variable
	// }

	template <typename _Predicate>
	int wait(_Predicate __p)
	{
		int result = 0;
		pthread_mutex_lock(&mutex);
		while (!__p())
			result = pthread_cond_wait(&cond, &mutex);
		pthread_mutex_unlock(&mutex);
		return result;
	}

	// 由于pthread_cond_timedwait可能被非signal和broadcast唤醒，所以下面注释的内容其实是没用的
	// int wait_until(DWORD dwMilliseconds){
	//     if (dwMilliseconds == INFINITE)
	//         return wait();

	//     pthread_mutex_lock(&mutex);

	//     timespec ts;
	//     pthread_stoptime(ts, dwMilliseconds);
	//     int result = pthread_cond_timedwait(&cond, &mutex, &ts);

	//     pthread_mutex_unlock(&mutex);
	//     return result;
	// }

	template <typename _Predicate>
	int wait_until(unsigned int dwMilliseconds, _Predicate __p)
	{
		if (dwMilliseconds == INFINITE)
			return wait(std::move(__p));

		pthread_mutex_lock(&mutex);

		timespec ts;
		pthread_stoptime(ts, dwMilliseconds);
		while (!__p())
		{
			int result = pthread_cond_timedwait(&cond, &mutex, &ts);
			if (result == wait_timeout)
			{
				// 大概率是超时，根据__p()的结构返回
				// 如果对超时时间有精度需要，以后这里可以比较下时间，再决定是否返回
				pthread_mutex_unlock(&mutex);
				return __p() ? wait_success : wait_timeout;
			}
			else if (result != wait_success)
			{
				// 其他错误， 返回
				pthread_mutex_unlock(&mutex);
				return result;
			}
			// result == 0,可能是虚假唤醒，继续循环
		}
		pthread_mutex_unlock(&mutex);
		return wait_success;
	}

	template <typename _Predicate>
	void signal(_Predicate __p)
	{
		pthread_mutex_lock(&mutex);
		__p();
		pthread_cond_signal(&cond);
		pthread_mutex_unlock(&mutex);
	}

	template <typename _Predicate>
	void broadcast(_Predicate __p)
	{
		pthread_mutex_lock(&mutex);
		__p();
		pthread_cond_broadcast(&cond);
		pthread_mutex_unlock(&mutex);
	}
};
